//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Effects;
using OpenLS.Spreadsheet.Functions;
using OpenLS.Spreadsheet.Parsing;
using OpenLS.Spreadsheet.UI.Internals.Resources;

namespace OpenLS.Spreadsheet.UI.Internals
{
    public partial class EditedCellResources
    {
        public EditedCellResources()
        {
            InitializeComponent();
        }
        private void onCommittingText (object sender, RoutedEventArgs args)
        {
            try
            {
                stopEditing(sender, true);

            }
            catch (FormulaException)
            {
            }
            args.Handled = true;

        }
        private void onPreviewKeyDown(object sender, KeyEventArgs args)
        {
            var frameworkElement = (FrameworkElement) sender;
            EditedCell c = EditionElement.GetEditedCell(frameworkElement);
            if (c == null)
                return;
            EditionMode mode = EditionElement.GetMode(frameworkElement);
            if (mode == EditionMode.Edit && isMoveKey(args.Key))
            {
                return;
            }
            ListBox selector;
            switch (args.Key)
            {
                case Key.System:
                    bool b = args.KeyboardDevice.IsKeyDown(Key.Enter);
                    if (b)
                    {
                        c.Text += Environment.NewLine;
                        var contentPresenter = frameworkElement.TemplatedParent as ContentPresenter;
                        var contentControl = contentPresenter.TemplatedParent as ContentControl;
                        c.SuggestWrap();
                        WorksheetGrid.SetVerticalOverflow(contentControl, true);
                        //WorksheetGrid.SetRowSpan(cc, i + 1); //\\
                        //\\tb.Height += 20;
                        args.Handled = true;
                    }
                    break;
                case Key.Enter:
                    bool arrayFormula = ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control) &&
                                        ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift);
                    try
                    {
                        stopEditingAndMove(frameworkElement,arrayFormula? CommitType.ArrayFormula: CommitType.Formula, EditingCommands.MoveDownByLine);
                    }
                    catch (InvalidFormulaException)
                    {}
                    args.Handled = true;
                    break;
                    case Key.PageDown:
                    case Key.PageUp:
                    if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
                    {
                        stopEditing(frameworkElement, true);
                    }
                    break;
                case Key.Down:
                    selector = (ListBox) EditionElement.GetSelector(frameworkElement);
                    if (selector != null && selector.Items.Count > 0)
                    {
                        selector.SelectedIndex++;
                        selector.ScrollIntoView(selector.SelectedItem);
                        args.Handled = true;
                        break;
                    }
                    moveEditingOrStopEditingAndMove(frameworkElement, CommitType.Formula, EditingCommands.MoveDownByLine, args);
                    args.Handled = true;
                    break;
                case Key.Up:
                    selector = (ListBox) EditionElement.GetSelector(frameworkElement);
                    if (selector != null && selector.Items.Count > 0)
                    {
                        selector.SelectedIndex--;
                        selector.ScrollIntoView(selector.SelectedItem);
                        args.Handled = true;
                        break;
                    }
                    moveEditingOrStopEditingAndMove((DependencyObject)sender, CommitType.Formula, EditingCommands.MoveUpByLine, args);
                    args.Handled = true;
                    break;
                case Key.Right:
                    moveEditingOrStopEditingAndMove((DependencyObject)sender, CommitType.Formula, EditingCommands.MoveRightByWord,
                                                    args);
                    args.Handled = true;
                    break;
                case Key.Left:
                    moveEditingOrStopEditingAndMove((DependencyObject)sender, CommitType.Formula, EditingCommands.MoveLeftByWord,
                                                    args);
                    args.Handled = true;
                    break;
                case Key.Tab:
                    selector = (ListBox) EditionElement.GetSelector(frameworkElement);
                    if (selector != null)
                    {
                        var cell = (EditedCell) frameworkElement.DataContext;
                        if (selector.SelectedItem != null)
                        {
                            cell.AcceptFunction((AddInFunction) (selector.SelectedItem));
                            var tb = (CellTextBox) frameworkElement;
                            tb.Source.Move(cell.Formula.LastIndexOf(cell.Formula.Tokens[cell.Formula.Tokens.Count - 1]));
                            args.Handled = true;
                            break;
                        }
                    }
                    if ((Keyboard.Modifiers & ModifierKeys.Shift) != 0)
                        stopEditingAndMove(frameworkElement, CommitType.Formula, EditingCommands.MoveLeftByWord);
                    else
                        stopEditingAndMove(frameworkElement, CommitType.Formula, EditingCommands.MoveRightByWord);
                    args.Handled = true;
                    break;
                case Key.Escape:
                    DependencyObject root = EditionElement.GetEditorRoot((DependencyObject) sender);
                    stopEditing(sender, false);
                    SpreadsheetElement.SetHighlight(root, null);
                    args.Handled = true;
                    break;
                case Key.Back:
                case Key.Delete:
                    // if (!c.RefusesSuggestions)
                    {
                        //   c.RefuseSuggestions();
                        // args.Handled = true;
                        //\\args.Handled = true;
                    }
                    break;
            }
            //\\grid.CalculatePositions();
            //\\grid.ArrangeChild(((FrameworkElement)sender), new Size (grid.ActualWidth, grid.ActualHeight));
        }

        private static bool isMoveKey(Key key)
        {
            switch (key)
            {
                case Key.Right:
                case Key.Left:
                case Key.Up:
                case Key.Down:
                    return true;
            }
            return false;
        }

        internal Delegate _CreateDelegate(Type delegateType, string handler)
        {
            return Delegate.CreateDelegate(delegateType, this, handler);
        }


        public void OnPreviewKeyDownInFormula(object sender, KeyEventArgs args)
        {
            var tb = (CellTextBox) sender;
            var editedCell = (EditedCell) tb.DataContext;
            if (editedCell == null)
                return;
            //\\ WorksheetGrid grid = ((FrameworkElement)sender).Parent as WorksheetGrid;
            switch (args.Key)
            {
                case Key.Enter:
                    FrameworkElement owner = EditionElement.GetWorkbookOwner(tb);
                    FrameworkElement grid = EditionElement.GetFocusGrid(owner);
                    grid.Focus();
                    bool isArrayFormula = ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
                                          && ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift);
                    try
                    {
                        stopEditingAndMove(tb, grid, isArrayFormula ? CommitType.ArrayFormula : CommitType.Formula,
                                           EditingCommands.MoveDownByLine);
                    }
                    catch (InvalidFormulaException)
                    {}
            //tb.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
                    // ContentControl o = Keyboard.FocusedElement as ContentControl;
                    args.Handled = true;
                    break;
                case Key.Escape:
                    stopEditing(sender, false);
                    SpreadsheetElement.SetHighlightFor(sender, null);
                    FrameworkElement owner2 = EditionElement.GetWorkbookOwner(tb);
                    FrameworkElement grid2 = EditionElement.GetFocusGrid(owner2);
                    grid2.Focus();
                    args.Handled = true;
                    break;
            }
        }

        private static void stopEditing(object sender, bool commit)
        {
            var frameworkElement = sender as FrameworkElement;
            EditedCell c = EditionElement.GetEditedCell(frameworkElement);
            if (commit)
                c.Commit(c.CommitText);
            UIElement grid = getGrid(frameworkElement); //\\ gr = null
            if (grid != null)
                grid.Focus();
            EditionElement.SetEditedCellFor(sender, null);
            //\\c.Worksheet.EditedCell = null;
        }

        private static void moveEditingOrStopEditingAndMove(DependencyObject sender, CommitType commit, RoutedCommand command,
                                                            KeyboardEventArgs args)
        {
            EditedCell c = EditionElement.GetEditedCell(sender);
            var tb = (CellTextBox) sender;
            if (c.Formula.ActiveReference != null)
            {
                c.Formula.ActiveReference.Move(getDirectionOf(command),
                                               (args.KeyboardDevice.Modifiers & ModifierKeys.Shift) != 0);
                tb.Source.Move(c.Formula.LastIndexOf(c.Formula.ActiveReference));
                return;
            }
            if (true)
            {
                if (!c.CanCommitSimple())
                {
                    //\\targetCell = targetCell.GetNeighbor(getDirectionOf(command));
                    Cell targetCell = c.Cell;
                    if (targetCell != null)
                    {
                        if (c.Formula.ActiveReference == null)
                        {
                            c.Formula.ActivateReference(targetCell);
                            tb.Source.Move(c.Formula.LastIndexOf(c.Formula.ActiveReference));
                        }
                        c.Formula.ActiveReference.Move(getDirectionOf(command),
                                                       (args.KeyboardDevice.Modifiers & ModifierKeys.Shift) != 0);
                        tb.Source.Move(c.Formula.LastIndexOf(c.Formula.ActiveReference));
                        return;
                    }
                }
            }
            stopEditingAndMove((FrameworkElement) sender, commit, command);
        }

        private static NavigationDirection getDirectionOf(RoutedCommand command)
        {
            if (command == EditingCommands.MoveDownByLine)
                return NavigationDirection.Down;
            if (command == EditingCommands.MoveUpByLine)
                return NavigationDirection.Up;
            if (command == EditingCommands.MoveRightByWord)
                return NavigationDirection.Right;
            if (command == EditingCommands.MoveLeftByWord)
                return NavigationDirection.Left;
            throw new NotSupportedException();
        }

        private static void stopEditingAndMove(FrameworkElement sender, CommitType commit, RoutedCommand command)
        {
            stopEditingAndMove(sender, sender as WorksheetGrid ?? getGrid(sender), commit, command);
        }

        private static void stopEditingAndMove(DependencyObject sender, UIElement gr,
            CommitType commit, RoutedCommand command)
        {
            var tb = (CellTextBox)sender;
            EditedCell c = EditionElement.GetEditedCell(sender);
            StopEditing(commit, c);
            //UIElement gr = sender as WorksheetGrid ?? GetGrid(tb);
            if (gr == null)
            {
                tb.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
            }
            else
            {
                gr.Focus();
                command.Execute(null, gr);
            }
            EditionElement.SetEditedCellFor(sender, null);
            //\\c.Worksheet.EditedCell = null;
        }
        private static void stopEditing(DependencyObject sender, UIElement gr,
                    CommitType commit)
        {
            var tb = (CellTextBox)sender;
            EditedCell c = EditionElement.GetEditedCell(sender);
            StopEditing(commit, c);
            //UIElement gr = sender as WorksheetGrid ?? GetGrid(tb);
            if (gr == null)
            {
                tb.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
            }
            else
            {
                gr.Focus();
            }
            EditionElement.SetEditedCellFor(sender, null);
            //\\c.Worksheet.EditedCell = null;
        }

        internal static void StopEditing(CommitType commit, EditedCell c)
        {
            if (commit == CommitType.None) return;
            try
            {
                c.Commit(c.CommitText, commit == CommitType.ArrayFormula);
                c.Worksheet.Workbook.View.ActiveSheet = c.Worksheet;
            }
            catch (DataValidationException dataValidationException)
            {
                throw new InvalidFormulaException(dataValidationException);
            }
            catch (Exception exp)
            {
                if (!BrowserInteropHelper.IsBrowserHosted)
                    MessageBox.Show(UIStringTable.FormulaHasErrors, "Spreadsheet", MessageBoxButton.OK);
                throw new InvalidFormulaException(exp);
            }
        }

        private static UIElement getGrid(FrameworkElement tb)
        {
            FrameworkElement e = tb;
            while (e != null)
            {
                if (e is WorksheetGrid)
                    return e;
                e = VisualTreeHelper.GetParent(e) as FrameworkElement;
            }
            return null;
        }

        private void functionListBox_MouseDoubleClick(object sender, MouseButtonEventArgs args)
        {
            var frameworkElement = (FrameworkElement)sender;
            var selector = (ListBox)EditionElement.GetSelector(frameworkElement);
            var cell = (EditedCell)frameworkElement.DataContext;
            if (selector.SelectedItem != null)
            {
                cell.AcceptFunction((AddInFunction)(selector.SelectedItem));
                CellTextBox tb = (CellTextBox) selector.Tag;
                tb.Source.Move(cell.Formula.LastIndexOf(cell.Formula.Tokens[cell.Formula.Tokens.Count - 1]));
                tb.Focus();
                args.Handled = true;
            }

        }

        private void onBorderLoaded(object sender, RoutedEventArgs e)
        {
            if (BrowserInteropHelper.IsBrowserHosted)
                return;

            var border = (FrameworkElement) sender;
            border.BitmapEffect = new DropShadowBitmapEffect {ShadowDepth = 2, Color = Colors.Gray};
        }

        private void functionListBox_KeyDown(object sender, KeyEventArgs args)
        {
            switch (args.Key)
            {
                case Key.Escape:
                    DependencyObject root = EditionElement.GetEditorRoot((DependencyObject) sender);
                    stopEditing(sender, false);
                    SpreadsheetElement.SetHighlight(root, null);
                    args.Handled = true;
                    break;
                case Key.Tab:
                    var frameworkElement = (FrameworkElement) sender;
                    var selector = (ListBox) EditionElement.GetSelector(frameworkElement);
                    if (selector != null)
                    {
                        var cell = (EditedCell) frameworkElement.DataContext;
                        if (selector.SelectedItem != null)
                        {
                            cell.AcceptFunction((AddInFunction) (selector.SelectedItem));
                            var cp = (ContentPresenter) selector.Tag;
                            DataTemplate dt = cp.ContentTemplate;
                            var tb = (CellTextBox) dt.FindName("editedCellTB", cp);
                            tb.Source.Move(cell.Formula.LastIndexOf(cell.Formula.Tokens[cell.Formula.Tokens.Count - 1]));
                            tb.Focus();
                        }
                        args.Handled = true;
                        break;
                    }
                    if ((Keyboard.Modifiers & ModifierKeys.Shift) != 0)
                        stopEditingAndMove(frameworkElement, CommitType.Formula, EditingCommands.MoveLeftByWord);
                    else
                        stopEditingAndMove(frameworkElement, CommitType.Formula, EditingCommands.MoveRightByWord);
                    args.Handled = true;
                    break;
            }
        }

        private void onFocusTextBoxobsolete(object sender, RoutedEventArgs e)
        {
            CellTextBox tb = (CellTextBox) sender;
            tb.Focus();
        }
    }
}